package com.zhsource.auth;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @Description: security安全配置类
 * @Author: Neuronet
 * @Date: 2023/10/5 22:28
 **/
@Configuration // 将当前类交给spring管理
@EnableWebSecurity // 开启security
//@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) // 开启注解授权
public class SecurityConfig {

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    //
    @Autowired
    private AuthenticationEntryPointImpl authenticationEntryPoint;

    @Autowired
    private AccessDenieHandleImpl accessDenieHandle;


    /**
     * @param authenticationConfiguration: 认证管理器配置对象
     * @Description: 获取AuthenticationManager（认证管理器），登录时认证使用
     * @Author: Neuronet
     * @Date: 2023/10/6 18:18
     * @Return: 认证管理器对象
     **/
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    /**
     * @Description: 密码加密器，会把客户端传来的密码进行加密，然后跟数据库中的密码做对比，要求数据库中的密码也是加密过的
     * 如果没有该加密器，spring security会报出异常：There is no PasswordEncoder mapped for the id "null"
     * @Author: Neuronet
     * @Date: 2023/10/5 22:36
     * @Return: 加密器对象
     **/
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * @param httpSecurity: 安全配置对象
     * @Description: web安全配置
     * @Author: Neuronet
     * @Date: 2023/10/5 22:34
     * @Return: 安全配置filter调用链对象
     **/
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable()// 1.CRSF禁用，因为不使用session
                // 2.基于JWT令牌，无需Session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                // 3.对于登录接口 允许匿名访问，也就是放行
//                .antMatchers("/**").anonymous()
                .antMatchers("/login/account","/minio/upload","/tourist/**" ,"/echarts/**","/course/export","/course/importTemplate","/course/importExcel").anonymous()


                // 4.静态文件允许访问，主要是swagger相关内容
                .antMatchers("/assets/**").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/v2/**").permitAll()
                .antMatchers("/swagger-ui/**").permitAll()
                // 5.除开要放行的接口，其他所有请求都需要登录状态校验
                .anyRequest().authenticated()
                // 6.关闭跨域检查，我们自己配置跨域，也可以使用Security的跨域配置
                .and().cors()
                // 7.配置认证过滤器
                .and().addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                // 8.配置自定义认证、授权失败处理器
                .exceptionHandling().accessDeniedHandler(accessDenieHandle).authenticationEntryPoint(authenticationEntryPoint);

        return httpSecurity.build();
    }
    public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        System.out.println(bCryptPasswordEncoder.encode("123"));
        System.out.println(bCryptPasswordEncoder.encode("123"));
        System.out.println(bCryptPasswordEncoder.matches("123", "$2a$10$O16hlzqDH.fPlZ1U8ENvCuh4jyiT20.QLYBgSCeU3JOMkcs.c3k9W"));
        System.out.println(bCryptPasswordEncoder.matches("123", "$2a$10$GNUQHqIm3pvZUWBsY5nPLe7PasaB.SUWSGhp.CQLGKiWuauwUB/zW"));
    }

}